{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1605\n"
     ]
    }
   ],
   "source": [
    "#从文件导入停用词表\n",
    "def stop_words(path):\n",
    "    stpwrd_dic = open(path, 'r')\n",
    "    stpwrd_content = stpwrd_dic.read()\n",
    "    stpwrd_dic.close()\n",
    "    return stpwrd_content.splitlines()#将停用词表转换为list  \n",
    "\n",
    "#合并搜集到的2份停用词表\n",
    "stop_words=list(set(stop_words(\"stop_words.txt\")+stop_words('chineseStopWords.txt')))\n",
    "print(len(stop_words))\n",
    "\n",
    "stop_words_path='stop_words_path.txt'\n",
    "\n",
    "with open(stop_words_path, 'w') as f:\n",
    "    f.writelines(stop_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2</td>\n",
       "      <td>合晟资产是一家专注于股票、债券等二级市场投资，为合格投资者提供专业资产管理服务的企业。公司业...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>公司的主营业务为向中小微企业、个体工商户、农户等客户提供贷款服务，自设立以来主营业务未发生过变化。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>公司立足于商业地产服务，致力于为商业地产开发、销售、运营全产业链提供一整套增值服务，业务覆盖...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2</td>\n",
       "      <td>公司经工商管理部门核准的经营范围为“投资咨询、经济信息咨询，企业管理咨询，品牌推广策划，公共...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2</td>\n",
       "      <td>该公司的主营业务为在中国境内(港、澳、台除外)开展保险代理销售，依托于自身的产品研究能力和专...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   0                                                  1\n",
       "0  2  合晟资产是一家专注于股票、债券等二级市场投资，为合格投资者提供专业资产管理服务的企业。公司业...\n",
       "1  2  公司的主营业务为向中小微企业、个体工商户、农户等客户提供贷款服务，自设立以来主营业务未发生过变化。\n",
       "2  1  公司立足于商业地产服务，致力于为商业地产开发、销售、运营全产业链提供一整套增值服务，业务覆盖...\n",
       "3  2  公司经工商管理部门核准的经营范围为“投资咨询、经济信息咨询，企业管理咨询，品牌推广策划，公共...\n",
       "4  2  该公司的主营业务为在中国境内(港、澳、台除外)开展保险代理销售，依托于自身的产品研究能力和专..."
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "#导入训练集\n",
    "\n",
    "train = pd.read_csv(\"training.csv\", header=None)\n",
    "train.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于 TF-IDF 算法的关键词抽取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Building prefix dict from /home/chenxiangkong/.local/lib/python3.6/site-packages/jieba/dict.txt ...\n",
      "Loading model from cache /tmp/jieba.cache\n",
      "Loading model cost 1.420093297958374 seconds.\n",
      "Prefix dict has been built succesfully.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0    {'投资': 0.9693054732081081, '管理': 0.50532617295...\n",
       "1    {'主营业务': 0.9486178553525, '中小': 0.747172968931...\n",
       "2    {'商业地产': 0.7356780001784615, '销售': 0.551758500...\n",
       "3    {'策划': 0.7356780001784615, '咨询': 0.51370089485...\n",
       "4    {'有限公司': 1.0082334038590361, '人寿保险': 0.8642000...\n",
       "Name: 1, dtype: object"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import jieba.analyse\n",
    "import unicodedata\n",
    "\n",
    "columns={}\n",
    "\n",
    "def is_number(s):\n",
    "    try:\n",
    "        float(s)\n",
    "        return True\n",
    "    except ValueError:\n",
    "        pass\n",
    " \n",
    "    try:\n",
    "        unicodedata.numeric(s)\n",
    "        return True\n",
    "    except (TypeError, ValueError):\n",
    "        pass\n",
    " \n",
    "    return False\n",
    "\n",
    "jieba.analyse.set_stop_words(stop_words_path)\n",
    "jieba.analyse.set_idf_path('idf.txt.big') \n",
    "def extract_tags(paragraph):\n",
    "    global columns\n",
    "    tags = jieba.analyse.extract_tags(paragraph, topK=len(paragraph), withWeight=True)\n",
    "    feat = {}\n",
    "    for tag in tags:\n",
    "        if(not is_number(tag[0])):\n",
    "            feat[tag[0]]=tag[1]\n",
    "            columns[tag[0]]=0\n",
    "    return feat\n",
    "\n",
    "X=train.iloc[:,1].apply(lambda paragraph:extract_tags(paragraph))\n",
    "X.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "29374\n"
     ]
    }
   ],
   "source": [
    "print(len(columns))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "特征维度29374"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.96930547, 0.50532617, 0.48465274, ..., 0.        , 0.        ,\n",
       "        0.        ],\n",
       "       [0.        , 0.        , 0.        , ..., 0.        , 0.        ,\n",
       "        0.        ],\n",
       "       [0.        , 0.0719118 , 0.        , ..., 0.        , 0.        ,\n",
       "        0.        ],\n",
       "       ...,\n",
       "       [0.        , 0.        , 0.        , ..., 0.15326625, 0.15326625,\n",
       "        0.        ],\n",
       "       [0.        , 0.05136557, 0.        , ..., 0.        , 0.        ,\n",
       "        0.13137107],\n",
       "       [0.        , 0.04582615, 0.        , ..., 0.        , 0.        ,\n",
       "        0.        ]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "#将文本特征转成二维数组\n",
    "\n",
    "def merge(tags,columns):\n",
    "    d=dict(columns , **tags)\n",
    "    return [v for k,v in d.items()]\n",
    "    \n",
    "lists = [merge(tags,columns) for tags in X]\n",
    "lists = np.array(lists)\n",
    "lists"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 5\n",
      "K-means end with clusters: 5\n",
      "v_measure_score: 0.20501943815697113\n",
      "calinski_harabaz_score: 57.84494384124362\n",
      "silhouette_score: 0.0006233043076269109\n",
      "K-means begin with clusters: 15\n",
      "K-means end with clusters: 15\n",
      "v_measure_score: 0.10778107564446482\n",
      "calinski_harabaz_score: 26.84056935349134\n",
      "silhouette_score: -0.03193355527714631\n",
      "K-means begin with clusters: 25\n",
      "K-means end with clusters: 25\n",
      "v_measure_score: 0.18705785950214063\n",
      "calinski_harabaz_score: 19.876204531258097\n",
      "silhouette_score: -0.12388241849972675\n",
      "K-means begin with clusters: 35\n",
      "K-means end with clusters: 35\n",
      "v_measure_score: 0.18060806191239587\n",
      "calinski_harabaz_score: 16.910041489234093\n",
      "silhouette_score: -0.15737747758369797\n",
      "K-means begin with clusters: 45\n",
      "K-means end with clusters: 45\n",
      "v_measure_score: 0.1793670514341241\n",
      "calinski_harabaz_score: 12.605241814866844\n",
      "silhouette_score: -0.16457020882992443\n"
     ]
    }
   ],
   "source": [
    "#训练查找最优K值\n",
    "\n",
    "from sklearn import metrics\n",
    "from sklearn.cluster import MiniBatchKMeans\n",
    "\n",
    "labels_true=train.iloc[:,0]\n",
    "\n",
    "def K_cluster_analysis(Ks, X):\n",
    "    SC_scores = []\n",
    "    CH_scores = []\n",
    "    VM_scores = []\n",
    "    for K in Ks:\n",
    "        print(\"K-means begin with clusters: {}\".format(K))\n",
    "        y_pred = MiniBatchKMeans(n_clusters = K).fit_predict(X)\n",
    "        print(\"K-means end with clusters: {}\".format(K))\n",
    "        \n",
    "        vm = metrics.v_measure_score(labels_true, y_pred) #本案例中训练数据有标签，可采用有参考模型的评价指标\n",
    "        print(\"v_measure_score: {}\".format(vm))\n",
    "        \n",
    "        ch = metrics.calinski_harabaz_score(X, y_pred) #这两个分数值越大则聚类效果越好\n",
    "        print(\"calinski_harabaz_score: {}\".format(ch))\n",
    "        \n",
    "        sh = metrics.silhouette_score(X, y_pred) #轮廓系数Silhouette Coefficient在大样本时计算太慢\n",
    "        print(\"silhouette_score: {}\".format(sh))\n",
    "        \n",
    "        CH_scores.append(ch)\n",
    "        SC_scores.append(sh)\n",
    "        VM_scores.append(vm)\n",
    "    return CH_scores,SC_scores,VM_scores\n",
    "\n",
    "Ks = [5,15,25,35,45]\n",
    "CH_scores,SC_scores,VM_scores=K_cluster_analysis(Ks,lists)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CH_Best_K: 5\n",
      "SC_Best_K: 5\n",
      "VM_Best_K: 5\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#去量纲\n",
    "ch = [float(x - np.min(CH_scores))/(np.max(CH_scores)- np.min(CH_scores)) for x in CH_scores]\n",
    "sc = [float(x - np.min(SC_scores))/(np.max(SC_scores)- np.min(SC_scores)) for x in SC_scores]\n",
    "vm = [float(x - np.min(VM_scores))/(np.max(VM_scores)- np.min(VM_scores)) for x in VM_scores]\n",
    "\n",
    "# 绘制不同K对应的聚类的性能，找到最佳模型／参数（分数最高）\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "%matplotlib inline\n",
    "\n",
    "plt.plot(Ks, np.array(ch), 'r-', label = 'CH_scores')\n",
    "plt.plot(Ks, np.array(sc), 'g-', label = 'SC_scores')\n",
    "plt.plot(Ks, np.array(vm), 'b-', label = 'VM_scores')\n",
    "plt.legend(loc='best')\n",
    "plt.xlabel( 'Calinski-Harabasz Index & Silhouette Coefficient & V Measure' )                                                                                    \n",
    "plt.ylabel( 'score' )\n",
    "\n",
    "### 最佳超参数\n",
    "index = np.unravel_index(np.argmax(CH_scores, axis=None), len(CH_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('CH_Best_K:',Best_K)\n",
    "\n",
    "index = np.unravel_index(np.argmax(SC_scores, axis=None), len(SC_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('SC_Best_K:',Best_K)\n",
    "\n",
    "index = np.unravel_index(np.argmax(VM_scores, axis=None), len(VM_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('VM_Best_K:',Best_K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 2\n",
      "K-means end with clusters: 2\n",
      "v_measure_score: 0.015158605895700407\n",
      "calinski_harabaz_score: 23.23876821945687\n",
      "silhouette_score: 0.052868466828774566\n",
      "K-means begin with clusters: 5\n",
      "K-means end with clusters: 5\n",
      "v_measure_score: 0.2062147876859299\n",
      "calinski_harabaz_score: 67.22160112222413\n",
      "silhouette_score: 0.003992890943954854\n",
      "K-means begin with clusters: 8\n",
      "K-means end with clusters: 8\n",
      "v_measure_score: 0.07381603181146397\n",
      "calinski_harabaz_score: 51.7891552961981\n",
      "silhouette_score: 0.020364770359170323\n",
      "K-means begin with clusters: 11\n",
      "K-means end with clusters: 11\n",
      "v_measure_score: 0.14411686026012357\n",
      "calinski_harabaz_score: 37.619452450667815\n",
      "silhouette_score: -0.05338055289407414\n"
     ]
    }
   ],
   "source": [
    "Ks = [2,5,8,11]\n",
    "CH_scores,SC_scores,VM_scores=K_cluster_analysis(Ks,lists)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CH_Best_K: 5\n",
      "SC_Best_K: 2\n",
      "VM_Best_K: 5\n"
     ]
    }
   ],
   "source": [
    "index = np.unravel_index(np.argmax(CH_scores, axis=None), len(CH_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('CH_Best_K:',Best_K)\n",
    "\n",
    "index = np.unravel_index(np.argmax(SC_scores, axis=None), len(SC_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('SC_Best_K:',Best_K)\n",
    "\n",
    "index = np.unravel_index(np.argmax(VM_scores, axis=None), len(VM_scores))\n",
    "Best_K = Ks[index[0]]\n",
    "print('VM_Best_K:',Best_K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 11\n",
      "K-means end with clusters: 11\n",
      "v_measure_score: 0.15422195286955903\n",
      "calinski_harabaz_score: 55.84885994789836\n",
      "silhouette_score: 0.0059152623674026605\n"
     ]
    }
   ],
   "source": [
    "from sklearn.cluster import KMeans\n",
    "\n",
    "K=11\n",
    "\n",
    "print(\"K-means begin with clusters: {}\".format(K))\n",
    "y_pred = KMeans(n_clusters=K, n_jobs=5).fit_predict(lists)\n",
    "print(\"K-means end with clusters: {}\".format(K))\n",
    "        \n",
    "vm = metrics.v_measure_score(labels_true, y_pred) #本案例中训练数据有标签，可采用有参考模型的评价指标\n",
    "print(\"v_measure_score: {}\".format(vm))\n",
    "        \n",
    "ch = metrics.calinski_harabaz_score(lists, y_pred) #这两个分数值越大则聚类效果越好\n",
    "print(\"calinski_harabaz_score: {}\".format(ch))\n",
    "        \n",
    "sh = metrics.silhouette_score(lists, y_pred) #轮廓系数Silhouette Coefficient在大样本时计算太慢 \n",
    "print(\"silhouette_score: {}\".format(sh))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "总结：\n",
    "1）直接使用jieba提取的特征进行聚类，相比TfidfVectorizer提取的特征，效果差很多。\n",
    "2）MiniBatchKMeans训练速度比KMeans快好多，KMeans太慢了，搜索参数先用MiniBatchKMeans搜，确定好超参数后再用KMeans"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
